package fr.ul.ade.prime.ui;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.BaseColumns;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.actionbarsherlock.app.SherlockListFragment;

import fr.ul.ade.R;
import fr.ul.ade.prime.database.Database;
import fr.ul.ade.prime.model.AdeWebOptions;
import fr.ul.ade.prime.model.Lesson;
import fr.ul.ade.prime.model.LessonType;
import fr.ul.ade.prime.model.ScheduleState;
import fr.ul.ade.prime.provider.AdeWebContract;
import fr.ul.ade.prime.util.Lists;

public class LessonList extends SherlockListFragment implements
		LoaderManager.LoaderCallbacks<Cursor>, BundleExtraNames,
		OnItemLongClickListener, DialogInterface.OnClickListener,
		View.OnClickListener {

	protected static final String TAG = LessonList.class.getSimpleName();

	// Nombre de jours chargés par chaque cursor
	protected static final int CURSOR_DAY_SPAN = 365;

	protected static final int DAY_TITLE_ID = -1;
	protected static final String DAY_TITLE_TIME = "-1"; //$NON-NLS-1$

	protected static final int NOON_SEPARATOR_ID = -2;
	protected static final String NOON_SEPARATOR_TIME = "12:00"; //$NON-NLS-1$

	// Données du cursor : date de début et fin des cours à récupérer
	protected static final String BUNDLE_SCHEDULE_ID = "schedule_id"; //$NON-NLS-1$
	protected static final String BUNDLE_START_DATE = "start_date"; //$NON-NLS-1$
	protected static final String BUNDLE_END_DATE = "end_date"; //$NON-NLS-1$

	public static final String DATE_FORMAT_DAY = "yyyy/MM/dd"; //$NON-NLS-1$

	public static final SimpleDateFormat dateDecoder = new SimpleDateFormat(
			DATE_FORMAT_DAY);

	public static final String GROUP_DATE_FORMAT_DAY = "EEEE dd MMMM"; //$NON-NLS-1$

	public static final SimpleDateFormat groupDateFormatter = new SimpleDateFormat(
			GROUP_DATE_FORMAT_DAY, Locale.FRANCE);

	protected List<Date> limits;

	protected ListLessonAdapter adapter;

	protected int displayedLessonPosition;

	protected boolean useAdeWebColors;

	protected ScheduleUpdateDialog dialog;

	protected Handler handler;

	protected boolean initialLoad;

	private final ContentObserver mLessonsObserver = new ContentObserver(
			new Handler()) {
		@Override
		public void onChange(boolean selfChange) {
			// Si jamais des données sont modifiées avant que le fragment soit
			// ajouté à l'activité
			if (getActivity() == null) {
				return;
			}

			// On récupère le loader
			int nLoaders = LessonList.this.limits.size() - 1;
			// Log.d(TAG, String.format(
			// "[mLessonsObserver.onChange] Refreshing %d loaders.",
			// nLoaders));
			final LoaderManager manager = LessonList.this.getLoaderManager();
			for (int loaderId = 0; loaderId < nLoaders; ++loaderId) {
				Loader<Cursor> loader = manager.getLoader(loaderId);
				// Log.d(TAG, String.format("\tLoader - %s",
				// loader == null ? loader : loader.getId()));
				if (loader != null) {
					// On force le rechargment des données.
					loader.forceLoad();
				}
			}
		}
	};

	private final ContentObserver mScheduleObserver = new ContentObserver(
			new Handler()) {
		@Override
		public void onChange(boolean selfChange) {
			// Si jamais des données sont modifiées avant que le fragment soit
			// ajouté à l'activité
			if (getActivity() == null) {
				return;
			}

			// Log.d(TAG, "[mScheduleObserver.onChange]");
			// On récupère le loader
			LoaderManager manager = LessonList.this.getLoaderManager();
			Loader<Cursor> loader = manager.getLoader(ScheduleQuery._TOKEN);
			if (loader != null) {
				loader.forceLoad();
			}// if
		}
	};

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.limits = Lists.newArrayList();
		this.initialLoad = true;
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View view = inflater.inflate(R.layout.lesson_list, container, false);
		return view;
	}

	@Override
	public void onViewCreated(View view, Bundle savedInstanceState) {
		super.onViewCreated(view, savedInstanceState);

		final ListView listView = this.getListView();
		this.adapter = new ListLessonAdapter();
		listView.setAdapter(this.adapter);
		listView.setCacheColorHint(0);
//		listView.setBackgroundColor(AdeWebOptions
//				.getBackgroundColor(AdeWebOptions.getTheme(this.getActivity())));
		// TODO Re-insert mark lesson
		// listView.setOnItemLongClickListener(this) ;
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);

		this.initLoaderIds();
	}

	private void initLoaderIds() {
		int period = ((ViewSchedule) this.getActivity()).getSchedulePeriod();
		Calendar calendar = Calendar.getInstance();
		this.limits.add(calendar.getTime());

		while (period > 0) {
			calendar.add(Calendar.DAY_OF_YEAR, CURSOR_DAY_SPAN);
			this.limits.add(calendar.getTime());
			period -= CURSOR_DAY_SPAN;
		}
	}

	private void startLoaders() {
		if (this.handler == null) {
			this.handler = new Handler();
		}

		this.handler.postDelayed(new Runnable() {
			@Override
			public void run() {
				LessonList ll = LessonList.this;
				// ll.adapter.clear();
				long scheduleId = ((ViewSchedule) ll.getActivity())
						.getScheduleId();
				int nLoaders = LessonList.this.limits.size() - 1;
				// Log.d(TAG, String.format("Creating %d loaders ...",
				// nLoaders));
				LoaderManager manager = ll.getLoaderManager();
				for (int loaderId = 0; loaderId < nLoaders; ++loaderId) {
					Bundle data = new Bundle();
					data.putLong(BUNDLE_SCHEDULE_ID, scheduleId);
					data.putString(BUNDLE_START_DATE, Database.dateFormatter
							.format(ll.limits.get(loaderId)));
					data.putString(BUNDLE_END_DATE, Database.dateFormatter
							.format(ll.limits.get(loaderId + 1)));
					manager.initLoader(loaderId, data, ll);
				}
			}
		},
				100 /* ms */);
	}

	@Override
	public void onAttach(Activity activity) {
		super.onAttach(activity);
		this.addObserver();
		this.adapter = new ListLessonAdapter();
		// ((ViewSchedule) activity).registerAdapter(this.adapter);
		// On sauvegarde les choix d'affichage de l'utilisateur, afin de ne pas
		// avoir à les rechercher à chaque requete
		this.useAdeWebColors = AdeWebOptions.useAdeWebColors(activity);

		Bundle args = new Bundle();
		args.putLong(BUNDLE_SCHEDULE_ID,
				((ViewSchedule) this.getActivity()).getScheduleId());
		this.getLoaderManager().initLoader(ScheduleQuery._TOKEN, args, this);
		// this.startLoaders();
	}

	private void addObserver() {
		long scheduleId = ((ViewSchedule) this.getActivity()).getScheduleId();
		Uri lessonsUri = AdeWebContract.Lesson.buildScheduleUri(scheduleId);
		Uri scheduleUri = ContentUris
				.withAppendedId(AdeWebContract.Schedule.CONTENT_URI, scheduleId);
		ContentResolver resolver = this.getActivity().getContentResolver();
		resolver.registerContentObserver(lessonsUri,
				true,
				this.mLessonsObserver);
		resolver.registerContentObserver(scheduleUri,
				true,
				this.mScheduleObserver);
	}

	@Override
	public void onDetach() {
		super.onDetach();
		this.removeObserver();
		// ((ViewSchedule) this.getActivity()).unregisterAdapter();
	}

	private void removeObserver() {
		ContentResolver resolver = this.getActivity().getContentResolver();
		resolver.unregisterContentObserver(this.mLessonsObserver);
		resolver.unregisterContentObserver(this.mScheduleObserver);
	}

	@Override
	public Loader<Cursor> onCreateLoader(int id, Bundle args) {
		Uri uri = null;
		String[] projection = null;
		String selection = null;
		String[] selectionArgs = null;
		String order = null;

		// Requested loader is a lesson loader
		if (id >= 0) {
			String start = args.getString(BUNDLE_START_DATE);
			String end = args.getString(BUNDLE_END_DATE);
			long scheduleId = args.getLong(BUNDLE_SCHEDULE_ID);
			uri = AdeWebContract.Lesson.buildScheduleBetweenUri(scheduleId,
					start,
					end);
			selection = String.format("%s = %s", //$NON-NLS-1$
					AdeWebContract.Lesson.LESSON_DELETED,
					Integer.valueOf(Lesson.NOT_DELETED));
			projection = LessonQuery.PROJECTION;
			order = AdeWebContract.Lesson.DEFAULT_SORT;
		} else {
			// Requested loader is a schedule loader
			uri = ContentUris
					.withAppendedId(AdeWebContract.Schedule.CONTENT_URI,
							args.getLong(BUNDLE_SCHEDULE_ID));
			projection = ScheduleQuery.PROJECTION;
			order = AdeWebContract.Schedule.DEFAULT_SORT;
		}// if
		return new CursorLoader(this.getActivity(), uri, projection, selection,
				selectionArgs, order);
	}// onCreateLoader(int, Bundle)

	@Override
	public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
		if (this.getActivity() == null) {
			return;
		}

		final ListView listView = this.getListView();
		// A lesson loader finished
		if (loader.getId() >= 0) {
			if (cursor.getCount() > 0) {
				this.adapter.addLessons(cursor);
				this.adapter.notifyDataSetChanged();
			}// if
			final LayoutInflater inflater = this.getActivity()
					.getLayoutInflater();

			final View view = this.getView();
			view.findViewById(R.id.list_loading).setVisibility(View.GONE);

			// TODO Gérer l'erreur produite par l'empty view
			if (listView.getEmptyView() == null) {
				final View emptyView = inflater
						.inflate(R.layout.lesson_list_empty,
								(ViewGroup) listView.getParent(),
								true).findViewById(android.R.id.empty);
				emptyView.setBackgroundColor(AdeWebOptions
						.getBackgroundColor(AdeWebOptions
								.getTheme(getActivity())));
				listView.setEmptyView(emptyView);

				final View updateText = emptyView
						.findViewById(R.id.update_schedule);
				updateText.setEnabled(true);
				updateText.setOnClickListener(this);
			}// if

		} else {// A schedule loader finished
			if (cursor.moveToNext()) {
				ScheduleState state = ScheduleState.getState(cursor
						.getInt(ScheduleQuery.SCHEDULE_STATE));
				this.handleScheduleState(state);
			} else {
				Toast.makeText(this.getActivity(),
						R.string.ViewSchedule_schedule_not_found,
						Toast.LENGTH_SHORT).show();
				this.getActivity().finish();
			}// if
		}// if
	}

	@Override
	public void onLoaderReset(Loader<Cursor> loader) {
		/* Nothing to be done. */
	}

	protected static String getFormattedDate(String date) {
		try {
			Date d = dateDecoder.parse(date);
			String formatted = groupDateFormatter.format(d);
			return String.format("%C%s", //$NON-NLS-1$
					Character.valueOf(formatted.charAt(0)),
					formatted.substring(1));
		} catch (ParseException e) {
			Log.d(TAG, "Invalid date !", e); //$NON-NLS-1$
		}
		return null;
	}

	@Override
	public void onListItemClick(ListView l, View v, int position, long id) {
		Bundle args = new Bundle();
		LessonView view = this.adapter.getItem(position);
		args.putLong(EXTRA_DISPLAYED_LESSON, view.getId());
		args.putParcelableArrayList(EXTRA_SCHEDULE_LESSONS,
				this.adapter.getLessons());
		args.putString(EXTRA_SCHEDULE_NAME,
				((ViewSchedule) this.getActivity()).getScheduleName());
		args.putString(EXTRA_LESSON_NAME, ((LessonChild) view).getTitle());
		args.putLong(EXTRA_SCHEDULE_ID,
				((ViewSchedule) this.getActivity()).getScheduleId());
		args.putInt(EXTRA_SCHEDULE_PERIOD,
				((ViewSchedule) this.getActivity()).getSchedulePeriod());
		Intent intent = new Intent(this.getActivity(), LessonDetails.class);
		intent.putExtras(args);
		this.getActivity().startActivity(intent);
		// Log.d(TAG,
		// "[Bundle]: "+intent.getParcelableArrayListExtra(EXTRA_SCHEDULE_LESSONS))
		// ;
	}

	@Override
	public boolean onItemLongClick(AdapterView<?> parent, View view,
			int position, long id) {
		// final Context context = this.getActivity() ;
		// AlertDialog.Builder builder = new AlertDialog.Builder(context) ;
		// ArrayAdapter<LessonType> dialogAdapter = new
		// ArrayAdapter<LessonType>(
		// context,
		// android.R.layout.select_dialog_singlechoice,
		// LessonType.values()) ;
		// LessonChild lesson = (LessonChild) this.adapter.getItem(position) ;
		// builder.setSingleChoiceItems(dialogAdapter,
		// lesson.getType().ordinal(), this) ;
		// builder.setTitle(R.string.ViewSchedule_mark_dialog_title) ;
		// builder.setIcon(Activity.RESULT_OK) ;
		// builder.create().show() ;
		// this.displayedLessonPosition = position ;

		return true;
	}

	@Override
	public void onClick(DialogInterface dialogInterface, int which) {
		LessonChild lesson = (LessonChild) this.adapter
				.getItem(this.displayedLessonPosition);
		Uri lessonUri = ContentUris
				.withAppendedId(AdeWebContract.Lesson.CONTENT_URI,
						lesson.getId());
		ContentValues values = new ContentValues();
		values.put(AdeWebContract.Lesson.LESSON_TYPE, Integer.valueOf(which));
		this.getActivity().getContentResolver()
				.update(lessonUri, values, null, null);
		lesson.setType(LessonType.values()[which]);
		this.adapter.notifyDataSetChanged();
		dialogInterface.dismiss();
	}

	protected int getBackgroundColor(LessonChild lesson) {
		int bgColor = AdeWebOptions.getBackgroundColor(AdeWebOptions
				.getTheme(this.getActivity()));
		if (this.useAdeWebColors) {
			bgColor = Color.parseColor(lesson.getColor());
		}
//		Log.d(TAG,
//				String.format("[gBgC]: rbg = %08x, useColor = %5b, (bg, lbg) = (%08x, %08x)",
//						bgColor,
//						this.useAdeWebColors,
//						AdeWebOptions.getBackgroundColor(AdeWebOptions
//								.getTheme(this.getActivity())),
//						Color.parseColor(lesson.getColor())));
		return bgColor;
	}

	protected int getRoomsColor() {
		int titleColor = Color.LTGRAY;
		if (this.useAdeWebColors) {
			titleColor = Color.BLACK;
		}
		return titleColor;
	}

	protected int getTitleColor() {
		int titleColor = Color.BLACK;
		if (!this.useAdeWebColors) {
			titleColor = AdeWebOptions.getTextColorViewSchedule(AdeWebOptions
					.getTheme(this.getActivity()));
		}
		return titleColor;
	}

	protected void handleScheduleState(ScheduleState state) {
		// Log.d(TAG, "[handleScheduleState]: " + state);
		switch (state) {
		case OTHER:
		case NOT_UPDATED:
		case UPDATED:
			if (this.initialLoad) {
				this.startLoaders();
				this.initialLoad = false;
			}// if
			this.hideDialog();
			break;
		default:
			this.displayDialog();
			this.updateDialog(state);
		}// switch
	}// handleScheduleState(ScheduleState)

	protected void hideDialog() {
		if (this.dialog != null) {
			this.dialog.dismiss();
			this.dialog = null;
		}// if
	}// hideDialog()

	protected void displayDialog() {
		if (this.dialog == null) {
			this.dialog = new ScheduleUpdateDialog(getActivity(),
					R.string.UpdateDialog_title);
			this.dialog.init();
		}// if
	}// hideDialog()

	protected void updateDialog(ScheduleState state) {
		this.dialog.updateMaxProgress(state);
	}// hideDialog()

	@Override
	public void onClick(View v) {
		ViewSchedule container = (ViewSchedule) this.getActivity();
		long scheduleId = container.getScheduleId();
		container.service.launchScheduleUpdate(scheduleId);
	}// onClick(View)

	protected interface LessonQuery {

		// Colonnes demandées au provider
		String[] PROJECTION = { BaseColumns._ID,
				AdeWebContract.Lesson.LESSON_CHANGE,
				AdeWebContract.Lesson.LESSON_COLOR,
				AdeWebContract.Lesson.LESSON_DATE,
				AdeWebContract.Lesson.LESSON_END_TIME,
				AdeWebContract.Lesson.LESSON_ROOMS,
				AdeWebContract.Lesson.LESSON_START_TIME,
				AdeWebContract.Lesson.LESSON_TITLE,
				AdeWebContract.Lesson.LESSON_TYPE };

		// colonnes des données demandés pour utiliser lors de la récupération
		// des données deouis le Cursor (appels à getString(int) p.ex.)
		int _ID = 0;
		int LESSON_CHANGE = 1;
		int LESSON_COLOR = 2;
		int LESSON_DATE = 3;
		int LESSON_END_TIME = 4;
		int LESSON_ROOMS = 5;
		int LESSON_START_TIME = 6;
		int LESSON_TITLE = 7;
		int LESSON_TYPE = 8;
	}

	protected interface ScheduleQuery {
		// id pour le loader
		int _TOKEN = -0x1;

		// colonnes demandées au provider
		String[] PROJECTION = { BaseColumns._ID,
				AdeWebContract.Schedule.SCHEDULE_STATUS };

		// colonnes des données demandés pour utiliser lors de la récupération
		// des données depuis le Cursor (appels à getString(int) p.ex.)
		int _ID = 0;
		int SCHEDULE_STATE = 1;
	}

	public class ListLessonAdapter extends BaseAdapter {

		private List<LessonView> items;

		public ListLessonAdapter() {
			super();
			this.items = Lists.newArrayList();
		}

		public void addLessons(Cursor cursor) {
			int datePos = this.items.isEmpty() ? -1 : 0;
			while (cursor.moveToNext()) {
				String date = cursor.getString(LessonQuery.LESSON_DATE);
				datePos = this.addDate(date, datePos);
				this.addOrReplace(cursor, datePos);
			}// while
		}

		public ArrayList<LessonBundle> getLessons() {
			ArrayList<LessonBundle> lessons = Lists.newArrayList();
			for (LessonView view : this.items) {
				if (view instanceof LessonChild) {
					lessons.add(lessons.size(), new LessonBundle(view.getId()));
				}// if
			}// for
			return lessons;
		}

		@Override
		public boolean hasStableIds() {
			return false;
		}

		protected int addDate(String date, int startPos) {
			DayGroup dayTitle = new DayGroup(date);
			int insertPos = 0;
			if (startPos != -1) {
				int cmpDate = this.items.get(startPos).compareTo(dayTitle);
				if (cmpDate == 0) {
					return startPos;
				}
				// La date se trouve à gauche de startPos
				if (cmpDate > 0) {
					insertPos = startPos - 1;
					while (insertPos >= 0
							&& this.items.get(insertPos).compareTo(dayTitle) > 0) {
						insertPos--;
					}// while
					if (insertPos < 0) {
						insertPos = 0;
					} else {
						int cmp = this.items.get(insertPos).compareTo(dayTitle);
						if (cmp == 0) {
							return insertPos;
						}// if
					}// if
				} else /* cmpDate < 0 */{
					// La date se trouve à droite de startPos
					insertPos = startPos + 1;
					int lastPos = this.items.size();
					while (insertPos < lastPos
							&& this.items.get(insertPos).compareTo(dayTitle) < 0) {
						insertPos++;
					}// while
					if (insertPos >= lastPos) {
						insertPos = lastPos;
					} else {
						int cmp = this.items.get(insertPos).compareTo(dayTitle);
						if (cmp == 0) {
							return insertPos;
						}// if
						insertPos++;
					}// if
				}// if
			}// if
			this.items.add(insertPos, dayTitle);
			// this.items.add(insertPos + 1, new NoonSeparator(date));
			return insertPos;
		}

		protected void addOrReplace(Cursor cursor, int startPos) {
			LessonView lessonView = new LessonChild(cursor);
			int insertPos = startPos, nLessons = this.getCount();
			while ((insertPos < nLessons)
					&& (this.getItem(insertPos).compareTo(lessonView) < 0)) {
				insertPos++;
			}// while

			if ((insertPos < nLessons)
					&& (this.getItem(insertPos).getId() == lessonView.getId())) {
				this.items.remove(insertPos);
			}// if
			this.items.add(insertPos, lessonView);
			String startHour = cursor.getString(LessonQuery.LESSON_START_TIME);
			if (startHour.compareTo("12:00") <= 0) {// Cours le matin
				// On regarde le prochain item, s'il s'agit d'un cours
				// l'après-midi, on ajoute un séparateur
				if (insertPos + 1 < this.items.size()) {
					LessonView next = this.items.get(insertPos + 1);
					if (next instanceof LessonChild) {
						LessonChild nextLesson = (LessonChild) next;
						if (nextLesson.startTime.compareTo("12:00") >= 0) {
							this.items.add(insertPos + 1, new NoonSeparator(
									nextLesson.date));
						}// if
					}// if
				}// if
			} else {// Cours l'après-midi
				// On regarde le précédant item, s'il s'agit d'un cours matinal,
				// on ajoute un séparateur
				LessonView previous = this.items.get(insertPos - 1);
				if (previous instanceof LessonChild) {
					LessonChild previousLesson = (LessonChild) previous;
					if (previousLesson.startTime.compareTo("12:00") <= 0) {
						this.items.add(insertPos, new NoonSeparator(
								previousLesson.date));
					}// if
				}// if
			}// if
		}// if

		@Override
		public int getCount() {
			// if (this.flag)
			// Log.d(TAG, "[getCount]: " + this.items.size());
			return this.items.size();
		}

		@Override
		public LessonView getItem(int position) {
			// if (this.flag)
			// Log.d(TAG, "[getItem]: " + position);
			return this.items.get(position);
		}

		@Override
		public long getItemId(int position) {
			return this.getItem(position).getId();
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			// Log.d(TAG, "[getView]: position - " + position);
			LayoutInflater inflater = LessonList.this.getActivity()
					.getLayoutInflater();
			return this.getItem(position)
					.getView(inflater, convertView, parent);
		}

		@Override
		public boolean areAllItemsEnabled() {
			return false;
		}

		@Override
		public boolean isEnabled(int position) {
			// TODO Modify to use a method (ListView.isEnabled())
			return (this.getItem(position) instanceof LessonChild);
		}

		@Override
		public boolean isEmpty() {
			return this.items.isEmpty();
		}

	}

	public abstract class LessonView implements Comparable<LessonView> {

		protected String date;
		protected String startTime;
		protected String endTime;
		protected long id;

		protected LessonView(String date, String startTime, String endTime,
				long id) {
			super();
			this.date = date;
			this.startTime = startTime;
			this.endTime = endTime;
			this.id = id;
		}

		@Override
		public int compareTo(LessonView another) {
			if (!this.date.equals(another.date)) {
				return this.date.compareTo(another.date);
			}
			if (!this.startTime.equals(another.startTime)) {
				return this.startTime.compareTo(another.startTime);
			}
			if (!this.endTime.equals(another.endTime)) {
				return another.endTime.compareTo(this.endTime);
			}
			return (int) (this.id - another.id);
		}

		public long getId() {
			return this.id;
		}

		@Override
		public String toString() {
			return String
					.format("%s=(%s, %s, %s, %d)", this.getClass().getSimpleName(), //$NON-NLS-1$
							this.date,
							this.startTime,
							this.endTime,
							Long.valueOf(this.id));
		}

		public abstract View getView(LayoutInflater inflater, View convertView,
				ViewGroup parent);
	}

	public class DayGroup extends LessonView {

		private String formattedDate;

		public DayGroup(String date) {
			super(date, DAY_TITLE_TIME, DAY_TITLE_TIME, DAY_TITLE_ID);
			this.formattedDate = LessonList.getFormattedDate(date);
		}

		@Override
		public String toString() {
			//			return String.format("(%s, %s)", super.toString(), this.formattedDate) ; //$NON-NLS-1$
			return String.format("%s=%s", this.getClass().getSimpleName(), //$NON-NLS-1$
					this.date);
		}

		@Override
		public View getView(LayoutInflater inflater, View convertView,
				ViewGroup parent) {
			View dayView = convertView;
			if (dayView == null
					|| dayView.findViewById(R.id.lesson_list_item_date) == null) {
				dayView = inflater.inflate(R.layout.lesson_item_list_header,
						parent,
						false);
				// dayView.setBackgroundColor(AdeWebOptions.getBackgroundColor(AdeWebOptions.getTheme(LessonList.this.getActivity())));
			}// if

			final TextView title = (TextView) dayView
					.findViewById(R.id.lesson_list_item_date);
			title.setText(this.formattedDate);
			title.setTextColor(AdeWebOptions.getTextColor(AdeWebOptions
					.getTheme(LessonList.this.getActivity())));

			return dayView;
		}
	}

	public class NoonSeparator extends LessonView {

		public NoonSeparator(String date) {
			super(date, NOON_SEPARATOR_TIME, NOON_SEPARATOR_TIME,
					NOON_SEPARATOR_ID);
		}

		@Override
		public View getView(LayoutInflater inflater, View convertView,
				ViewGroup parent) {
			View separator = convertView;
			if (separator == null
					|| separator.findViewById(R.id.lesson_list_noon_separator) == null) {
				separator = inflater
						.inflate(R.layout.lesson_list_noon_separator,
								parent,
								false);
				separator
						.setBackgroundDrawable(getResources()
								.getDrawable(AdeWebOptions
										.getBackgroundStried(AdeWebOptions
												.getTheme(LessonList.this
														.getActivity()))));
			}// if

			return separator;
		}

		@Override
		public String toString() {
			return this.getClass().getSimpleName();
		}
	}

	public class LessonChild extends LessonView {

		private int change;
		private String color;
		private String rooms;
		private String title;
		private LessonType type;

		public LessonChild(Cursor cursor) {
			super(cursor.getString(LessonQuery.LESSON_DATE), cursor
					.getString(LessonQuery.LESSON_START_TIME), cursor
					.getString(LessonQuery.LESSON_END_TIME), cursor
					.getLong(LessonQuery._ID));
			this.change = cursor.getInt(LessonQuery.LESSON_CHANGE);
			this.color = cursor.getString(LessonQuery.LESSON_COLOR);
			this.rooms = cursor.getString(LessonQuery.LESSON_ROOMS);
			this.title = cursor.getString(LessonQuery.LESSON_TITLE);
			this.type = LessonType.values()[cursor
					.getInt(LessonQuery.LESSON_TYPE)];
		}

		public String getColor() {
			return this.color;
		}

		public String getTitle() {
			return this.title;
		}

		public void setType(LessonType type) {
			this.type = type;
		}

		@Override
		public String toString() {
			//			return String.format("(%s, %s)", super.toString(), this.title) ; //$NON-NLS-1$
			return String.format("%s=%s %s-%s", //$NON-NLS-1$
					this.getClass().getSimpleName(),
					this.date,
					this.startTime,
					this.endTime);
		}

		@Override
		public View getView(LayoutInflater inflater, View convertView,
				ViewGroup parent) {
			View childView = convertView;
			if (childView == null
					|| childView.findViewById(R.id.block_title) == null) {
				childView = inflater.inflate(R.layout.lesson_item_list_block,
						parent,
						false);
				;
			}// if

			final TextView titleView = (TextView) childView
					.findViewById(R.id.block_title);
			// TODO Externalize strings
			String titleContent = this.title;
			// if (this.type.equals(LessonType.IMPORTANT))
			// titleContent += " (important)";
			// if (this.type.equals(LessonType.EXAM))
			// titleContent += " (partiel)";
			titleView.setText(titleContent);
			titleView.setTextColor(LessonList.this.getTitleColor());

			final TextView startTimeView = (TextView) childView
					.findViewById(R.id.start_time);
			startTimeView.setText(this.startTime);

			final TextView endTimeView = (TextView) childView
					.findViewById(R.id.end_time);
			endTimeView.setText(this.endTime);

			final TextView roomsView = (TextView) childView
					.findViewById(R.id.block_subtitle);
			String displayedRooms = this.rooms;
			if (TextUtils.isEmpty(this.rooms)) {
				displayedRooms = LessonList.this.getResources()
						.getString(R.string.Lesson_room_unknown);
			}// if
			roomsView.setText(displayedRooms);
			roomsView.setTextColor(LessonList.this.getRoomsColor());

			if (this.change != Lesson.BIG_CHANGE) {
				final ImageView bigChange = (ImageView) childView
						.findViewById(R.id.change);
				bigChange.setVisibility(View.INVISIBLE);
			}

			childView.setBackgroundColor(LessonList.this
					.getBackgroundColor(this));

			return childView;
		}
	}

	public static class LessonBundle implements Parcelable {

		long lessonId;

		public LessonBundle(long lessonId) {
			super();
			this.lessonId = lessonId;
		}

		public LessonBundle(Parcel in) {
			this(in.readLong());
		}

		@Override
		public int describeContents() {
			return 0;
		}

		@Override
		public void writeToParcel(Parcel dest, int flags) {
			dest.writeLong(this.lessonId);
		}

		@Override
		public String toString() {
			return String.format("id=%d", Long.valueOf(this.lessonId)); //$NON-NLS-1$
		}

		@Override
		public boolean equals(Object o) {
			if (o instanceof LessonBundle) {
				LessonBundle l = (LessonBundle) o;
				return this.lessonId == l.lessonId;
			}
			return super.equals(o);
		}

		@Override
		public int hashCode() {
			return Long.valueOf(this.lessonId).hashCode();
		}

		public static final Parcelable.Creator<LessonBundle> CREATOR = new Creator<LessonList.LessonBundle>() {

			@Override
			public LessonBundle createFromParcel(Parcel source) {
				return new LessonBundle(source);
			}

			@Override
			public LessonBundle[] newArray(int size) {
				return new LessonBundle[size];
			}
		};

	}

}// class LessonList